package br.com.educa.controle;

import br.com.educa.modelo.financeiro.Caixas;
import br.com.educa.modelo.financeiro.Cartao;
import br.com.educa.modelo.financeiro.Cheques;
import br.com.educa.modelo.financeiro.HistoricoCheque;
import br.com.educa.modelo.financeiro.Historicos;
import br.com.educa.modelo.financeiro.LancamentosAlunos;
import br.com.educa.modelo.financeiro.MovimentacoesCaixas;
import br.com.educa.modelo.financeiro.Negociacoes;
import br.com.educa.modelo.financeiro.enumerator.SituacaoLancamentoAluno;
import br.com.educa.modelo.financeiro.enumerator.TipoLancamento;
import br.com.educa.modelo.security.Usuario;
import flexjson.JSONDeserializer;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.joda.time.format.DateTimeFormat;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.roo.addon.web.mvc.controller.json.RooWebJson;
import org.springframework.roo.addon.web.mvc.controller.scaffold.RooWebScaffold;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils;

@RooWebJson(jsonObject = Negociacoes.class)
@Controller
@RequestMapping("/negociacoeses")
@RooWebScaffold(path = "negociacoeses", formBackingObject = Negociacoes.class)
public class NegociacoesController {

    @RequestMapping(value = "/{id}", headers = "Accept=application/json")
    @ResponseBody
    public ResponseEntity<java.lang.String> showJson(@PathVariable("id") Long id) {
        Negociacoes negociacoes = Negociacoes.findNegociacoes(id);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json; charset=utf-8");
        if (negociacoes == null) {
            return new ResponseEntity<String>(headers, HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<String>(negociacoes.toJson(), headers, HttpStatus.OK);
    }

    @RequestMapping(headers = "Accept=application/json")
    @ResponseBody
    public ResponseEntity<java.lang.String> listJson() {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json; charset=utf-8");
        List<Negociacoes> result = Negociacoes.findAllNegociacoeses();
        return new ResponseEntity<String>(Negociacoes.toJsonArray(result), headers, HttpStatus.OK);
    }

    @Transactional(rollbackFor = Throwable.class)
    @RequestMapping(method = RequestMethod.POST, headers = "Accept=application/json")
    public ResponseEntity<java.lang.String> createFromJson(@RequestBody String json, Principal usuario) {
        try {
            Negociacoes negociacoes = Negociacoes.fromJsonToNegociacoes(json);
            Date d = new Date();
            negociacoes.setVersion(0);
            negociacoes.setDataNegociacao(d);
            final Usuario currentUser = (Usuario) ((Authentication) usuario).getPrincipal();
            negociacoes.setAutorizador(currentUser);
            negociacoes.setControle(currentUser.getControle());
            negociacoes.persist();
            Caixas caixa = Caixas.findCaixasesByUsuarioOpen(currentUser).getSingleResult();
            List<LancamentosAlunos> lancamentos = negociacoes.getNegociacaoLancamentosAlunos();
            //calcular desconto para estes lançamentos. Mesma idéia do calculo de porcentagem de movimentação.
            if(negociacoes.getDescontoReais() > 0.00){
	            Double porcentagem = 0.00;
	            Double valorMovimentacaoBase = negociacoes.getTotalNegociacao();
	            Double valorLancamento = 0.00;
	            Double valorLancTemp = 0.00;
	            Integer ct = 1;
	            Integer tt = lancamentos.size();
	            for(LancamentosAlunos lac : lancamentos){ 
	            	if(ct < tt){
	            		porcentagem = (double) ((lac.getValorBase() / valorMovimentacaoBase) * 100);//pega a porcentagem do todo.
	            		valorLancamento = (double) Math.ceil((porcentagem * negociacoes.getTotalNegociacaoPagar()) / 100);//multiplica na movimentacao.
	            		valorLancTemp = valorLancTemp + valorLancamento;
	            		ct++;
	            	}else{
	            		valorLancamento = negociacoes.getTotalNegociacaoPagar() - valorLancTemp;
	            	}
	            	//calcular o valor do desconto.
	            	lac.setDesconto(lac.getValorBase() - valorLancamento);
	            	lac.setValorPago(valorLancamento);
	            	lac.merge();
	            	porcentagem = 0.00;
	            	valorLancamento = 0.00;
	            }
            }else{
            	for(LancamentosAlunos lac : lancamentos){
            		lac.setValorPago(lac.getValorBase());
            		lac.merge();
            	}
            }
            //implementando as movimentações.
            List<MovimentacoesCaixas> mov = negociacoes.getNegociacaoMovimentacaoCaixas();
            Double valorMovimentacaoBase = negociacoes.getTotalNegociacao();
            Double soma = 0.00;
            Double porcentagem = 0.00;
            Double valorMovimentacao = 0.00;
            for (MovimentacoesCaixas movimentacao : mov) {
            	//grava o cheque se existir.
                Cheques cheque = movimentacao.getCheque();
                if (cheque != null) {
                    cheque.setVersion(0);
                    cheque.setDataCheque(d);
                    cheque.setControle(currentUser.getControle());
                    cheque.persist();
                    HistoricoCheque hisCheque = new HistoricoCheque();
                    hisCheque.setVersion(0);
                    hisCheque.setCheque(cheque);
                    hisCheque.setDataHistorico(d);
                    hisCheque.setCaixa(caixa);
                    hisCheque.setConta(caixa.getConta());
                    hisCheque.persist();
                    movimentacao.setCheque(cheque);
                }
                //gravar o cartão.
                if(movimentacao.getTipoPagamento().toString().equals("Cartao")){
                	//gravar o cartão.
                	//avaliar se é crédito ou débito.
                	Cartao cartao = new Cartao();
                	cartao.setNegociacao(negociacoes);
                	cartao.setValorCartao(movimentacao.getValorMovimentacao());
                	if(movimentacao.getTipoPagamento() == "CartaoDebito"){
                		cartao.setTipoCartao("Debito");
                	}else{
                		cartao.setTipoCartao("Credito");
                	}
                	cartao.setVersion(0);
                	cartao.persist();
                }
                Double valorLancamentosTemp = 0.00;
                Integer total = lancamentos.size();
                Integer cont = 1;
                for (LancamentosAlunos lanc : lancamentos) {
                    LancamentosAlunos lancamento = LancamentosAlunos.findLancamentosAlunos(lanc.getId());
                    lancamento.setValorPago(lanc.getValorPago());
                    lancamento.setDesconto(lanc.getDesconto());
                    lancamento.setDataPagamento(d);
                    lancamento.setSituacaoLancamento(SituacaoLancamentoAluno.Paga);
                    Double desconto = lanc.getDesconto();
                    if (desconto != 0.0) {
                        lancamento.setObservacao("Desconto concedido pelo usuário " + currentUser.getPessoa().getNome());
                        //calcular o desconto.
                    }
                    lancamento.setNegociacao(negociacoes);
                    lancamento.merge();
                    if (cont == total) {
                        valorMovimentacao = (movimentacao.getValorMovimentacao() - valorLancamentosTemp);
                    } else {
                        porcentagem = (double) ((lancamento.getValorPago() / valorMovimentacaoBase) * 100);//pega a porcentagem do todo.
                        valorMovimentacao = (double) Math.ceil((porcentagem * movimentacao.getValorMovimentacao()) / 100);//multiplica na movimentacao.
                        valorLancamentosTemp = valorLancamentosTemp + valorMovimentacao;
                        cont++;
                    }
                    MovimentacoesCaixas movi = new MovimentacoesCaixas();
                    movi.setNegociacao(negociacoes);
                    movi.setCaixa(caixa);
                    movi.setDataMovimentacao(d);
                    movi.setHistorico(lanc.getHistorico());
                    movi.setContaCredito(caixa.getConta());
                    Historicos historicoLancamento = Historicos.findHistoricos(lanc.getHistorico().getId());
                    movi.setContaDebito(historicoLancamento.getPlanoContas());
                    movi.setObservacao("Recebimento da " + historicoLancamento.getHistorico() + ", do aluno " + lanc.getAluno().getPessoaAluno().getNome());
                    movi.setDocumento(historicoLancamento.getHistorico() + " número " + lanc.getId());
                    movi.setTipoLancamento(TipoLancamento.Credito);
                    movi.setTipoPagamento(movimentacao.getTipoPagamento());
                    movi.setValorMovimentacao(valorMovimentacao);
                    movi.setCheque(movimentacao.getCheque());
                    movi.setControle(currentUser.getControle());
                    movi.persist();
                    porcentagem = 0.00;
                    valorMovimentacao = 0.00;
                }
            }
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Type", "application/json");
            Negociacoes neg = Negociacoes.findNegociacoes(negociacoes.getId());
            //return new ResponseEntity<String>(headers, HttpStatus.CREATED);
            return new ResponseEntity<String>(neg.toJson(), headers, HttpStatus.CREATED);
        } catch (Exception e) {
            e.printStackTrace();
        }
		return null;
    }

    @RequestMapping(value = "/jsonArray", method = RequestMethod.POST, headers = "Accept=application/json")
    public ResponseEntity<java.lang.String> createFromJsonArray(@RequestBody String json) {
        for (Negociacoes negociacoes : Negociacoes.fromJsonArrayToNegociacoeses(json)) {
            negociacoes.persist();
        }
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        return new ResponseEntity<String>(headers, HttpStatus.CREATED);
    }

    @RequestMapping(method = RequestMethod.PUT, headers = "Accept=application/json")
    public ResponseEntity<java.lang.String> updateFromJson(@RequestBody String json) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        Negociacoes negociacoes = Negociacoes.fromJsonToNegociacoes(json);
        if (negociacoes.merge() == null) {
            return new ResponseEntity<String>(headers, HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<String>(headers, HttpStatus.OK);
    }

    @RequestMapping(value = "/jsonArray", method = RequestMethod.PUT, headers = "Accept=application/json")
    public ResponseEntity<java.lang.String> updateFromJsonArray(@RequestBody String json) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        for (Negociacoes negociacoes : Negociacoes.fromJsonArrayToNegociacoeses(json)) {
            if (negociacoes.merge() == null) {
                return new ResponseEntity<String>(headers, HttpStatus.NOT_FOUND);
            }
        }
        return new ResponseEntity<String>(headers, HttpStatus.OK);
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE, headers = "Accept=application/json")
    public ResponseEntity<java.lang.String> deleteFromJson(@PathVariable("id") Long id) {
        Negociacoes negociacoes = Negociacoes.findNegociacoes(id);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        if (negociacoes == null) {
            return new ResponseEntity<String>(headers, HttpStatus.NOT_FOUND);
        }
        negociacoes.remove();
        return new ResponseEntity<String>(headers, HttpStatus.OK);
    }

    @RequestMapping(method = RequestMethod.POST, produces = "text/html")
    public String create(@Valid Negociacoes negociacoes, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            populateEditForm(uiModel, negociacoes);
            return "negociacoeses/create";
        }
        uiModel.asMap().clear();
        negociacoes.persist();
        return "redirect:/negociacoeses/" + encodeUrlPathSegment(negociacoes.getId().toString(), httpServletRequest);
    }

    @RequestMapping(params = "form", produces = "text/html")
    public String createForm(Model uiModel) {
        populateEditForm(uiModel, new Negociacoes());
        return "negociacoeses/create";
    }

    @RequestMapping(value = "/{id}", produces = "text/html")
    public String show(@PathVariable("id") Long id, Model uiModel) {
        addDateTimeFormatPatterns(uiModel);
        uiModel.addAttribute("negociacoes", Negociacoes.findNegociacoes(id));
        uiModel.addAttribute("itemId", id);
        return "negociacoeses/show";
    }

    @RequestMapping(produces = "text/html")
    public String list(@RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
        if (page != null || size != null) {
            int sizeNo = size == null ? 10 : size.intValue();
            final int firstResult = page == null ? 0 : (page.intValue() - 1) * sizeNo;
            uiModel.addAttribute("negociacoeses", Negociacoes.findNegociacoesEntries(firstResult, sizeNo));
            float nrOfPages = (float) Negociacoes.countNegociacoeses() / sizeNo;
            uiModel.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages));
        } else {
            uiModel.addAttribute("negociacoeses", Negociacoes.findAllNegociacoeses());
        }
        addDateTimeFormatPatterns(uiModel);
        return "negociacoeses/list";
    }

    @RequestMapping(method = RequestMethod.PUT, produces = "text/html")
    public String update(@Valid Negociacoes negociacoes, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            populateEditForm(uiModel, negociacoes);
            return "negociacoeses/update";
        }
        uiModel.asMap().clear();
        negociacoes.merge();
        return "redirect:/negociacoeses/" + encodeUrlPathSegment(negociacoes.getId().toString(), httpServletRequest);
    }

    @RequestMapping(value = "/{id}", params = "form", produces = "text/html")
    public String updateForm(@PathVariable("id") Long id, Model uiModel) {
        populateEditForm(uiModel, Negociacoes.findNegociacoes(id));
        return "negociacoeses/update";
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = "text/html")
    public String delete(@PathVariable("id") Long id, @RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
        Negociacoes negociacoes = Negociacoes.findNegociacoes(id);
        negociacoes.remove();
        uiModel.asMap().clear();
        uiModel.addAttribute("page", (page == null) ? "1" : page.toString());
        uiModel.addAttribute("size", (size == null) ? "10" : size.toString());
        return "redirect:/negociacoeses";
    }

    void addDateTimeFormatPatterns(Model uiModel) {
        uiModel.addAttribute("negociacoes_datanegociacao_date_format", DateTimeFormat.patternForStyle("M-", LocaleContextHolder.getLocale()));
    }

    void populateEditForm(Model uiModel, Negociacoes negociacoes) {
        uiModel.addAttribute("negociacoes", negociacoes);
        addDateTimeFormatPatterns(uiModel);
        uiModel.addAttribute("lancamentosalunoses", LancamentosAlunos.findAllLancamentosAlunoses());
        uiModel.addAttribute("movimentacoescaixases", MovimentacoesCaixas.findAllMovimentacoesCaixases());
        uiModel.addAttribute("usuarios", Usuario.findAllUsuarios());
    }

    String encodeUrlPathSegment(String pathSegment, HttpServletRequest httpServletRequest) {
        String enc = httpServletRequest.getCharacterEncoding();
        if (enc == null) {
            enc = WebUtils.DEFAULT_CHARACTER_ENCODING;
        }
        try {
            pathSegment = UriUtils.encodePathSegment(pathSegment, enc);
        } catch (UnsupportedEncodingException uee) {
        }
        return pathSegment;
    }
}
